package com.swxy.club.service;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.swxy.club.dto.User;
import com.swxy.club.dto.bo.LoginUserBO;
import com.swxy.club.dto.bo.UserBo;
import com.swxy.club.dto.bo.UserPageBo;
import com.swxy.club.dto.vo.CurrentUserVO;
import com.swxy.club.enums.Gender;
import com.swxy.club.enums.UserStatus;
import com.swxy.club.exceptions.UserNotFoundException;
import com.swxy.club.mapper.UserMapper;
import com.swxy.club.utils.JWTUtil;
import com.swxy.club.utils.SessionUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.EnumUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author 易
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {


    private static final List<String> ALLOW_TYPE = Arrays.asList("image/jpeg", "image/png");
    private final RedisTemplate<String, Object> redisTemplate;

    @Value("${file.upload.path}")
    private String uploadPath;

    @Override
    public User getUserByIdNumber(String number) {

        LambdaQueryWrapper<User> queryWrapper = new QueryWrapper<User>()
                .lambda()
                .eq(User::getIdNumber, number)
                .or().
                eq(User::getPhone, number)
                .or()
                .eq(User::getEmail, number)
                .or()
                .eq(User::getId, number);

        User user = this.getOne(queryWrapper);
        if (user == null){
            throw new UserNotFoundException();
        }
        return user;
    }

    @Override
    public void addUser(UserBo form ,HttpSession session) {

        CurrentUserVO currentUser = SessionUtil.getCurrentUser(session);

        Assert.isTrue(form.getGender()== null || EnumUtils.isValidEnum(Gender.class, form.getGender()), "性别非法");
        User user = BeanUtil.copyProperties(form, User.class);
        user.setIdNumber(String.valueOf(this.baseMapper.getMaxNumber()+1));
        user.setGender(Gender.valueOf(form.getGender()));
        user.setRoleId("2");
        user.setPassword(DigestUtil.md5Hex(form.getPassword()));
        user.setCreateId(currentUser.getId());
        user.setUpdateId(currentUser.getId());
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        this.save(user);

    }

    @Override
    public String uploadImage(MultipartFile file) {

        // 校验类型
        String contentType = file.getContentType();
        Assert.isTrue(ALLOW_TYPE.contains(contentType), "上传文件类型非法");

        try {
            // 获取项目路径

            String imagePath = uploadPath;

            File dir = new File(imagePath);
            if (!dir.exists()){
                dir.mkdirs();
            }

            // 获取原始文件名 & 后缀
            String originalFilename = file.getOriginalFilename();
            String fileSuffix = "";
            if (originalFilename != null && originalFilename.contains(".")) {
                fileSuffix = originalFilename.substring(originalFilename.lastIndexOf("."));
            }

            // 生成唯一文件名（带后缀）
            String uniqueFileName = UUID.randomUUID().toString().replace("-","") + fileSuffix;

            // 保存文件
            File destFile = new File(dir, uniqueFileName);
            file.transferTo(destFile);


            return "http://localhost:8888/user-serv/image/" + uniqueFileName;

        } catch (IOException e) {
            throw new RuntimeException("图片上传失败：" + e.getMessage(), e);
        }

    }

    @Override
    public Map<String, Object> login(LoginUserBO loginUserBO , HttpSession session) {

        // 校验用户名是否存在
        User user = this.getOne(new QueryWrapper<User>().lambda().eq(User::getIdNumber, loginUserBO.getNumber()));
        Assert.notNull(user, "用户账号不存在");

        // 校验用户状态是否正常
        UserStatus status = user.getStatus();
        Assert.isTrue(status == UserStatus.NORMAL, "用户账号已被停用");

        // 校验密码是否正确
        boolean isPasswordValid = StrUtil.equalsIgnoreCase(DigestUtil.md5Hex(loginUserBO.getPassword()),user.getPassword());
        Assert.isTrue(isPasswordValid, "密码错误");

        // 校验验证码是否正确
        // 获取验证码
        String key = "verifyCode:" + session.getId();
        String verifyCode = (String) redisTemplate.opsForValue().get(key);

        Assert.notNull(verifyCode,"验证码已失效");
        Assert.isTrue(StrUtil.equalsIgnoreCase(loginUserBO.getVerifyCode(), verifyCode), "验证码错误");

        // 登录成功后清除验证码
        session.removeAttribute("verifyCode");

        // 构建返回结果
        Map<String, Object> map = new HashMap<>();

        // 生成 JWT Token
        Map<String, String> payload = new HashMap<>();

        payload.put("id", String.valueOf(user.getId()));
        payload.put("number", user.getIdNumber());
        payload.put("username", user.getRealName());

        String token = JWTUtil.getToken(payload);
        map.put("token", token);

        session.setAttribute("user_session", user);
        session.setMaxInactiveInterval(60*60);
        return map;

    }

    @Override
    public CurrentUserVO getCurrentUser(HttpSession session) {
        return SessionUtil.getCurrentUser(session);
    }

    @Override
    public List<User> selectUsers( List<Long> ids) {
        Assert.notNull(ids, "用户id不能为空");
        return this.listByIds(ids);
    }

    @Override
    public Page<User> pageSelect(UserPageBo form) {

        Page<User> userPage = new Page<>(form.getPageNum(), form.getPageSize());
        return this.page(userPage);
    }

}
